package org.poptest.junit4;

import org.junit.Before;
import org.junit.runner.notification.RunListener;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.TestClass;
import org.poptest.bootstrap.Bootstrapper;
import org.poptest.bootstrap.BootstrapperFactory;
import org.poptest.model.Context;
import org.poptest.junit4.annotation.DelegateTo;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author Alan Roche
 *         Date: 26/01/11
 *         Time: 21:28
 */
public class BootstrapRunner extends NotifyingRunner {
    private final Bootstrapper bootstrapper;

    public BootstrapRunner(final Class<?> testClass) throws InitializationError {
        super(testClass, DelegateTo.class, "value");
        this.bootstrapper = BootstrapperFactory.create(testClass);
    }

    @Override
    protected FrameworkMethod wrapTestFrameworkMethod(final Class<?> key, final FrameworkMethod frameworkMethod) {
        return new BootstrapFrameworkMethod(bootstrapper, key, frameworkMethod) {
            @Override
            public Object invokeExplosively(Object target, Object... params) throws Throwable {
                bootstrapper.beforeTestMethod(new Context(target));
                return super.invokeExplosively(target, params);
            }
        };
    }

    @Override
    public List<? extends FrameworkMethod> getFirstBeforeMethods(TestClass testClass) {
        class BootstrapBeforeTestMethod extends BootstrapFrameworkMethod {
            public BootstrapBeforeTestMethod(Bootstrapper bootStrapper, Class<?> keyClass) {
                super(bootStrapper, keyClass);

            }
            @Override
            public Object invokeExplosively(Object target, Object... params) throws Throwable {
                bootstrapper.beforeTestConfiguration(new Context(target));
                return null;
            }
        }

        return Arrays.asList(new BootstrapBeforeTestMethod(this.bootstrapper, Before.class)) ;
    }

    @Override
    public List<? extends FrameworkMethod> getFirstBeforeClassMethods(TestClass testClass) {
        class BootstrapBeforeClassMethod extends BootstrapFrameworkMethod {
            public BootstrapBeforeClassMethod(Bootstrapper bootStrapper, Class<?> keyClass) {
                super(bootStrapper, keyClass, getBeforeClassDummyMethod());

            }
            @Override
            public Object invokeExplosively(final Object target, final Object... params) throws Throwable {
                bootstrapper.beforeClass(new Context(BootstrapRunner.this.getTestClass().getJavaClass()));
                return null;
            }
        }

        return Arrays.asList(new BootstrapBeforeClassMethod(this.bootstrapper, Before.class)) ;
    }
}
